//
// Created by luge812 on 2025/1/28.
//
#include <iostream>
#include <easyx.h>
#include <vector>
#include <ctime>
class Sprite
{
public:
    Sprite():Sprite(0,0){};
    Sprite(int x, int y):m_x(x),m_y(y),m_color(RED){};
    virtual void draw()
    {
        //绘制矩形
        //设置填充颜色
        setfillcolor(m_color);
        fillrectangle(m_x,m_y,m_x+10,m_y+10);
    }
    void moveBy(int dx,int dy)
    {
        m_x += dx;
        m_y += dy;
    }
    bool collision(const Sprite& other)
    {
        return m_x == other.m_x && m_y == other.m_y;
    }
protected:
    int m_x;
    int m_y;
    COLORREF m_color;  //颜色
};
/*蛇*/
class Snake : public Sprite
{
public:
    Snake():Snake(0,0){}
    Snake(int x, int y) : Sprite(x,y),dir(VK_RIGHT)
    {
        //定义三节身体
        nodes.push_back(Sprite(20,0));
        nodes.push_back(Sprite(10,0));
        nodes.push_back(Sprite(0,0));
    }
    void draw() override
    {
        for(int i = 0; i < nodes.size(); i++)
        {
            nodes[i].draw();
        }
    }
    void bodyMove()
    {
//        for(size_t i = 1; i < nodes.size(); i++)
//        {
//            nodes[i] = nodes[i - 1];
//        }
//身体跟着蛇头
          for(size_t i = nodes.size()-1; i > 0; i--)
          {
              nodes[i] = nodes[i - 1];
          }
          //移动蛇头
        switch(dir)
        {
            case VK_UP:
                nodes[0].moveBy(0,-10);
                break;
            case VK_DOWN:
                nodes[0].moveBy(0,10);
                break;
            case VK_LEFT:
                nodes[0].moveBy(-10,0);
                break;
            case VK_RIGHT:
                nodes[0].moveBy(10,0);
                break;
        }

    }
    bool collision (const Sprite& other)
    {
        return nodes[0].collision(other);
    }
    void incrment()
    {
        nodes.push_back(Sprite());
    }
private:
    std::vector<Sprite> nodes;
public:
    int dir;   //蛇的方向
};

/*食物*/
class Food :public Sprite
{
public:
    Food():Sprite(0,0)
    {
        changeFoodPos();
    }
    void draw()override
    {
        setfillcolor(m_color);
        fillrectangle(m_x,m_y,m_x+10,m_y+10);
    }
    void changeFoodPos()
    {
        //随机生成坐标
        m_x = rand() % 64*10;
        m_y = rand() % 48*10;
    }
};





//游戏场景
class GameScene
{
public:
    GameScene()
    {

    };
    void run()
    {
        BeginBatchDraw();//双缓冲绘图
        cleardevice();
        snake.draw();
        food.draw();
        EndBatchDraw();
        //改变蛇的坐标
        snake.bodyMove();
        //改变蛇的移动方向
        //碰撞吃食物
        snakeEatFood();
        ExMessage msg = { 0 };
        while( peekmessage(&msg,EX_KEY))
        {
            onMsg(msg);
        }
    }
    //响应键盘鼠标信息
    void onMsg(const ExMessage& msg)
    {
        //如果有键盘消息
        if(msg.message == WM_KEYDOWN)
        {
            //判断具体的是哪个按键按下 virtual key code 虚拟键码
            if( msg.vkcode == VK_UP||msg.vkcode == VK_DOWN||msg.vkcode == VK_LEFT||msg.vkcode == VK_RIGHT)
            {
                snake.dir = msg.vkcode;
            }
            switch (msg.vkcode) {
                case VK_UP:
                    if(snake.dir != VK_DOWN)
                        snake.dir = msg.vkcode;
                    break;
                    case VK_DOWN:
                    if(snake.dir != VK_UP)
                        snake.dir = msg.vkcode;
                    break;
                    case VK_LEFT:
                    if(snake.dir != VK_RIGHT)
                        snake.dir = msg.vkcode;
                    break;
                    case VK_RIGHT:
                    if(snake.dir != VK_LEFT)
                        snake.dir = msg.vkcode;
                    break;
            }
        }
    }
    void snakeEatFood()
    {
        if(snake.collision(food))//如果蛇和食物产生碰撞
        {
            //蛇的节数增加
            snake.incrment();
            //食物重新产生在别的位置
            food.changeFoodPos();
        }
    }
private:
    Snake snake;
    Food food;
};



int main()
{
    initgraph(640,480,EX_SHOWCONSOLE);
    //设置随机种子
    srand(time(nullptr));
    GameScene scene;
    while(true)
    {
        scene.run();
        Sleep(50);
    }
    getchar();

    return 0;
}